//
//  NSOperationViewController.m
//  多线程编程
//
//  Created by Guo Rui on 2017/7/14.
//  Copyright © 2017年 GR Harry. All rights reserved.
//

#import "NSOperationViewController.h"

@interface NSOperationViewController ()

@end

@implementation NSOperationViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
//    [self mutiblocks];
    [self mutiOperations];
//    [self testMainQueue];
    
}

- (void)testMainQueue {
    NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"1 %@", [NSThread currentThread]);
    }];
    
    NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"2 %@", [NSThread currentThread]);
    }];
    
    NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"3 %@", [NSThread currentThread]);
    }];
    
    NSOperationQueue *queue = [NSOperationQueue mainQueue];
    [queue addOperation:operation1];
    [queue addOperation:operation2];
    [queue addOperation:operation3];
}

- (void)mutiOperations {
    
    /**
        iOS中队列有两种类型：主队列、其他队列。
        1. 主队了是串行队列。
           凡是添加到主队列中的任务（NSOperation），都会放到主线程中执行
        2. 其他队列通过设置maxConcurrentOperationCount，变为串行或并发。
           添加到这种队列中的任务（NSOperation），就会自动放到子线程中执行。
     */
    
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
    
        NSOperationQueue *queue = [[NSOperationQueue alloc] init];
        
        NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
            sleep(1);
            NSLog(@"1 %@", [NSThread currentThread]);
        }];
        
        NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
            sleep(1);
            NSLog(@"2 %@", [NSThread currentThread]);
            [queue addOperationWithBlock:^{
                NSLog(@"4 %@", [NSThread currentThread]);
            }];
        }];
        
        NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{
            sleep(1);
            NSLog(@"3 %@", [NSThread currentThread]);
        }];
        
        
#if 0
        /*
         maxConcurrentOperationCount属性：
         1. maxConcurrentOperationCount默认情况下为-1，表示不进行限制，默认为并发执行。
         2. 当maxConcurrentOperationCount为1时，进行串行执行。
         3. 当maxConcurrentOperationCount大于1时，进行并发执行，当然这个值不应超过系统限制，即使自己设置一个很大的值，系统也会自动调整。
         */
        queue.maxConcurrentOperationCount = 1;
#endif
        
#if 0
        /*
         1. 不能添加相互依赖，会死锁，比如 A依赖B，B依赖A。
         2. 可以使用 removeDependency 来解除依赖关系。
         3. 可以在不同的队列之间依赖，反正就是这个依赖是添加到任务身上的，和队列没关系。
         4. Operations 添加到 queue 之后，绝对不要再修改 Operations 对象。因为 Operations 对象可能会在任何时候运行，因此改变依赖或数据会产生不利的影响。
         */
        // 建立任务之间的依赖关系
        [operation1 addDependency:operation2];
        [operation2 addDependency:operation3];
#endif
        /* 
         1. 当maxConcurrentOperationCount = 1时 并且 没有依赖关系时，任务会按添加的顺序执行。
         2. 当maxConcurrentOperationCount = 1时 并且 添加了依赖关系时， 任务按照依赖关系决定的顺序执行。
         */
        
        
#if 0
        // 并发执行3个任务
        [queue addOperation:operation1];
        [queue addOperation:operation2];
        [queue addOperation:operation3];
#else
        /*
         这个方法可以同时添加多个operation
         waitUntilFinished，是否阻塞当前线程, 直到全部任务完成。
         */
        [queue addOperations:@[operation1, operation2, operation3] waitUntilFinished:YES];
        
        // 阻塞当前线程，直到队列中所有的任务全部完成。
        [queue waitUntilAllOperationsAreFinished];
        NSLog(@"after finish");
#endif
    });
}


- (void)mutiblocks {
    
    /* 
     在没有使用NSOperationQueue、单独使用NSBlockOperation的情况下，NSBlockOperation也是在主线程执行操作，并没有开启新线程。
     */
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        // 这个任务会在当前线程中执行。
        NSLog(@"1 %@", [NSThread currentThread]);
    }];
    
    /*
     NSBlockOperation还提供了一个方法addExecutionBlock:，通过addExecutionBlock:就可以为NSBlockOperation添加额外的操作，这些额外的操作就会在 其他线程 并发执行。
    */
    [operation addExecutionBlock:^{
        NSLog(@"2 %@", [NSThread currentThread]);
    }];
    
    [operation addExecutionBlock:^{
        NSLog(@"3 %@", [NSThread currentThread]);
    }];
    
    // 相当于 并发执行这些任务（block）
//    [operation start];
    
    
    // 如果用queue执行，任务一就不会在当前线程中执行了。
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [queue addOperation:operation];
}

@end
